package org.xteam.sled.semantic;

import java.util.Map;

import org.xteam.sled.semantic.exp.Exp;
import org.xteam.sled.semantic.exp.ExpAdd;
import org.xteam.sled.semantic.exp.ExpConst;
import org.xteam.sled.semantic.exp.ExpPC;
import org.xteam.sled.semantic.exp.IExpRewriter;


public class Label extends SequenceElement {

	private String name;
	private boolean isActual;

	public Label(String name, boolean isActual) {
		this.name = name;
		this.isActual = isActual;
	}
	
	public Label(String name) {
		this(name, true);
	}
	
	public boolean isLabel() {
		return true;
	}
	
	public boolean isActual() {
		return isActual;
	}

	@Override
	public SequenceElement substitutePC(int k, Exp addBitsToPC) {
		return this;
	}
	
	public String toString() {
		if (isActual)
			return name + ":";
		return "LATENT(" + name + "):";
	}

	public void addBinding(Map<String, Exp> bindings, int position) {
		if (isActual) {
			if (bindings.containsKey(name))
				throw new RuntimeException("label " + name + " appears twice in disjunct");
			bindings.put(name, new ExpAdd(new ExpPC(), new ExpConst(position / GlobalState.pcUnitBits)));
		}
	}

	@Override
	public SequenceElement substitute(IExpRewriter subs) {
		if (! isActual) {
			throw new RuntimeException("not complete");
		}
		return this;
	}
	
	public SequenceElement injectLatent() {
		return new Label(name, false);
	}
	
	public SequenceElement actualize(boolean actualsOk) {
		/* actualize (LABEL (LATENT e) :: t, seqs') =
	  	    case e
	  		 of U.BINDING_INSTANCE (name, wild, _) =>
	  		    if actualsOK then
	  		      actualize(t, if wild then seqs' else LABEL(ACTUAL name) :: seqs')
	  		    else
	  		      Impossible.impossible "latent label becoming actual"
	  		  | _ =>
	  		    if ignorable e then actualize(t, seqs')
	  		    else Impossible.impossible "type of latent-label expression"
	  	    end*/
	  	    
		throw new RuntimeException("should be checked");
	}
	
	//  let fun ignorable (U.VAR _) = true
	//  | ignorable (U.INSTANCE _) = true
	//  | ignorable (U.INSTANCE_INPUT (e, {cons, operand})) = ignorable e
    //          /* only if it's a constructor-typed input, but I can't check */
	//  | ignorable _ = false

}
